/**
 * Base32 解码 - 修正版
 */
function base32Decode(encoded) {
    const base32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    encoded = encoded.toUpperCase().replace(/=+$/, '').replace(/\s/g, '');

    // 检查是否有无效字符
    for (let char of encoded) {
        if (base32Chars.indexOf(char) === -1) {
            throw new Error(`Invalid Base32 character: ${char}`);
        }
    }

    let bits = '';
    for (let i = 0; i < encoded.length; i++) {
        const char = encoded[i];
        const value = base32Chars.indexOf(char);
        bits += value.toString(2).padStart(5, '0');
    }

    const bytes = [];
    for (let i = 0; i + 8 <= bits.length; i += 8) {
        const byte = bits.substr(i, 8);
        bytes.push(parseInt(byte, 2));
    }

    return new Uint8Array(bytes);
}
function intToBytes(num) {
    const bytes = new Uint8Array(8);
    for (let i = 7; i >= 0; i--) {
        bytes[i] = num & 0xff;
        num = Math.floor(num / 256);
    }
    return bytes;
}
/**
 * HMAC-SHA1 计算 - 使用 Web Crypto API
 */
async function hmacSHA1(key, message) {
    try {
        // 导入密钥
        const cryptoKey = await crypto.subtle.importKey(
            'raw',
            key,
            { name: 'HMAC', hash: 'SHA-1' },
            false,
            ['sign']
        );

        // 计算 HMAC
        const signature = await crypto.subtle.sign(
            'HMAC',
            cryptoKey,
            message
        );

        return new Uint8Array(signature);
    } catch (error) {
        console.error('HMAC-SHA1 计算失败:', error);
        throw error;
    }
}
/**
 * 动态截断
 */
function dynamicTruncation(hmac) {
    const offset = hmac[hmac.length - 1] & 0xf;

    // 确保不会越界
    if (offset + 4 > hmac.length) {
        throw new Error('HMAC 长度不足');
    }

    return (
        ((hmac[offset] & 0x7f) << 24) |
        ((hmac[offset + 1] & 0xff) << 16) |
        ((hmac[offset + 2] & 0xff) << 8) |
        (hmac[offset + 3] & 0xff)
    );
}

/**
 * 生成数字代码
 */
function generateDigitCode(dynamicBinaryCode, digits) {
    const modulus = Math.pow(10, digits);
    const code = dynamicBinaryCode % modulus;
    return code.toString().padStart(digits, '0');
}

export async function generateTOTP(secret, options = {}){
    const {
        digits = 6,
        timeStep = 30,
        timestamp = Date.now(),
        prefix = '',
        suffix = '',
    } = options;
    // 将 Base32 密钥解码为字节数组
    const key = base32Decode(secret);

    // 计算时间窗口 和 过期时间
    let s = Math.floor(timestamp / 1000);
    const timeCounter = Math.floor(s / timeStep);
    const timeout =  (timeCounter+1) * timeStep - s;
    console.log(`${timeout}秒后过期`)

    // 将时间计数器转换为字节数组
    const timeCounterBytes = intToBytes(timeCounter);
    console.log('时间计数器字节:', Array.from(timeCounterBytes));

    // 使用 HMAC-SHA1 计算哈希
    const hmac = await hmacSHA1(key, timeCounterBytes);
    console.log('HMAC 长度:', hmac.length);
    console.log('HMAC 内容:', Array.from(hmac));

    // 动态截断获取动态二进制代码
    const dynamicBinaryCode = dynamicTruncation(hmac);
    console.log('动态二进制代码:', dynamicBinaryCode);

    // 生成指定位数的数字密码
    return generateDigitCode(dynamicBinaryCode, digits);
}

export async function generateTOTP_fix(secret, prefix = '', suffix = '') {
    let code = await generateTOTP(secret)
    return prefix + code + suffix;
}